﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;

namespace PostscriptTools.Intellisense {

	[Export(typeof(ITaggerProvider))]
	[ContentType("postscript")]
	[TagType(typeof(ErrorTag))]
	[Order(Before = "default")]
	internal class ErrorTaggerProvider : ITaggerProvider {
		[Import]
		internal IBufferTagAggregatorFactoryService AggregatorFactory = null;
		public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag {
			// create a single tagger for each buffer.
			Func<ITagger<T>> sc = delegate() { return new ErrorTagger(buffer, this.AggregatorFactory) as ITagger<T>; };
			return buffer.Properties.GetOrCreateSingletonProperty<ITagger<T>>(sc);
		}
	}


	internal sealed class ErrorTagger : ITagger<ErrorTag> {
		readonly ITextBuffer _buffer;
		readonly ITagAggregator<PostscriptTokenTag> _aggregator;

		public ErrorTagger(ITextBuffer buffer, IBufferTagAggregatorFactoryService aggregatorFactory) {
			_buffer = buffer;
			_aggregator = aggregatorFactory.CreateTagAggregator<PostscriptTokenTag>(buffer);
		}

		public IEnumerable<ITagSpan<ErrorTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
			if (spans.Count == 0 || this._buffer.CurrentSnapshot.Length == 0) {
				//there is no content in the buffer
				yield break;
			}
			foreach (IMappingTagSpan<PostscriptTokenTag> tagSpan in this._aggregator.GetTags(spans)) {
				if (tagSpan.Tag.Type == PostscriptToken.PsError) {
					var tagSpans = tagSpan.Span.GetSpans(spans[0].Snapshot); // map the spans to the current snapshot
					var tag = tagSpan.Tag as PostscriptErrorTag;
					if (tag != null) {
						yield return new TagSpan<ErrorTag>(tagSpans[0], new ErrorTag(PredefinedErrorTypeNames.SyntaxError, tag.Message));
					}
				}
			}
		}

		// the Classifier tagger is translating buffer change events into TagsChanged events, so we don't have to
#pragma warning disable 67
		public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
#pragma warning restore
	}

}